use std::time::Duration;
use std::sync::{Arc,Mutex};
use std::sync::atomic::{Ordering,AtomicBool,AtomicUsize};
use crate::game;
use game::{Piece,Loc,Board};

#[derive(Copy,Clone,PartialEq)]
// Message from Engine -> Algo
pub enum MessageEA {
    Get(Piece,Duration),
    Stop,
    None,
}
// Message from Algo -> Engine
#[derive(Copy,Clone,PartialEq)]
pub enum MessageAE {
    MoveLoc(Loc),
    MoveSwap,
    MovePass,
    None,
}

#[derive(Clone)]
pub struct State {
    _board: Arc<Mutex<Board>>,
    _board_lastmove_loc: Arc<AtomicUsize>,
    _use_forbidden: Arc<AtomicBool>,
    _in_think_step: Arc<AtomicBool>,
    _message_ea: Arc<Mutex<MessageEA>>,
    _message_ae: Arc<Mutex<MessageAE>>,
}
impl State {
    pub fn new() -> State {
        State {
            _board: Arc::new(Mutex::new(game::board_make_empty())),
            _board_lastmove_loc: Arc::new(AtomicUsize::new(Loc::MAX)),
            _use_forbidden: Arc::new(AtomicBool::new(false)),
            _in_think_step: Arc::new(AtomicBool::new(false)),
            _message_ea: Arc::new(Mutex::new(MessageEA::None)),
            _message_ae: Arc::new(Mutex::new(MessageAE::None)),
        }
    }

    pub fn now_board(&self) -> Board {
        let board = self._board.lock().unwrap();
        *board
    }
    pub fn new_board_set(&mut self, from:&Board) {
        let mut board = self._board.lock().unwrap();
        *board = *from
    }

    pub fn board_lastmove_loc(&self) -> Loc {
        self._board_lastmove_loc.load(Ordering::Acquire)
    }
    pub fn board_lastmove_loc_set(&mut self, loc:Loc) {
        self._board_lastmove_loc.store(loc, Ordering::Release)
    }

    pub fn use_forbidden(&self) -> bool {
        self._use_forbidden.load(Ordering::Acquire)
    }
    pub fn use_forbidden_set(&mut self, on:bool) {
        self._use_forbidden.store(on, Ordering::Release)
    }

    pub fn in_think_step(&self) -> bool {
        self._in_think_step.load(Ordering::Acquire)
    }
    pub fn in_think_step_set(&mut self, on:bool) {
        self._in_think_step.store(on, Ordering::Release)
    }

    pub fn poll_message_ea(&self) -> MessageEA {
        let m = self._message_ea.lock().unwrap();
        *m
    }
    pub fn take_message_ea(&mut self) {
        self.send_message_ea(MessageEA::None)
    }
    pub fn send_message_ea(&mut self, msg:MessageEA) {
        let mut m = self._message_ea.lock().unwrap();
        *m = msg
    }

    pub fn poll_message_ae(&self) -> MessageAE {
        let m = self._message_ae.lock().unwrap();
        *m
    }
    pub fn take_message_ae(&mut self) {
        self.send_message_ae(MessageAE::None)
    }
    pub fn send_message_ae(&mut self, msg:MessageAE) {
        let mut m = self._message_ae.lock().unwrap();
        *m = msg
    }
}
